
/*
 * A join is performed when one wants to wait for a thread to finish. 
 * A thread calling routine may launch multiple threads then wait for them 
 * to finish to get the results. One waits for the completion of the 
 * threads with a join. 
*/



#include <iostream>
#include <pthread.h>


using namespace std;


// Global variables and constants
// ------------------------------

static const int NUMBER_OF_THREADS = 10;

pthread_mutex_t myCounterLock = PTHREAD_MUTEX_INITIALIZER;
int myCounter = 0;


// Function prototypes
// -------------------

void* threadFunction(void*);



// Main function (creates the threads, waits until all finished (joins) and returns)
// -------------

int main (int argc, char **argv)
{
    pthread_t threadID[NUMBER_OF_THREADS];
    
    // Create all threads...
    
    for (int i = 0; i < NUMBER_OF_THREADS; i++)
    {
        // Argument description of pthread_create:
        // 1. pointer to thread variable itself
        // 2. attributes of the thread
        // 3. start function of the thread
        // 4. argument given to the start function (to pass multiple arguments, use a pointer to a structure)
        
        pthread_create(&threadID[i], NULL, threadFunction, NULL);
    }
    
    // Wait until all threads terminated...
    
    for (int j = 0; j < NUMBER_OF_THREADS; j++)
    {
        // Argument description of pthread_join
        // 1. pointer to the thread variable itself (wait on this threds terminates)
        // 2. The return value of the start function will be stored at this location
        
        pthread_join(threadID[j], NULL);
    }
        
    // Print out the final value of the global variable "myCounter"...
    
    cout << endl << "Final counter value: " << dec << myCounter << endl;
    
    return 0;
}


// Implementation of the "thread functionality"
// --------------------------------------------

void* threadFunction(void* theDummyArgument)
{
    // Because all threads accesses the same variable, a mutex protection is nessessary...
    
    pthread_mutex_lock(&myCounterLock);
    
    myCounter++;
    cout << "Thread id: " << hex << pthread_self() << ", increments counter: " << dec << myCounter << endl;
        
    pthread_mutex_unlock(&myCounterLock);
    
    return NULL;
}
